package find.prj.lists;

import java.util.Collection;
import java.util.List;
import java.util.ListIterator;

public class OneWayList<T> extends AbstractListClass<T> {
	
	private ListNode<T> FirstNode;
	
	public OneWayList() {
		this.FirstNode = null;
		this.Size = 0;
	}

	public OneWayList(T value) {
		this();
		this.add(value);		
	}
	
	public OneWayList(T[] valueArray) {
		this();
		ListIterator<T> iter = this.listIterator();
		for (T value : valueArray)
			iter.add(value);
	}

	public OneWayList(Collection<T> list) {
		this();
		this.addAll(list);
	}
	
	@SuppressWarnings("unchecked")
	private void setFirstNode(ListNode<? extends Object> node) {
		FirstNode = (ListNode<T>) node;
	}
	
	@Override
	public void clear() {
		this.FirstNode = null;
		this.Size = 0;
	}

	@Override
	public ListIterator<T> listIterator(int index) {
		return new OneWayListIterator<T>(index);
	}

	@Override
	public List<T> subList(int fromIndex, int toIndex) {
		OneWayList<T> newList = new OneWayList<T>();
		ListIterator<T> iter = this.listIterator(fromIndex);
		while (iter.nextIndex() != toIndex)
			newList.add(iter.next());
		return newList;
	}

	// ----------------------------------- OneWayListIterator ------------------------------------
	@SuppressWarnings("hiding")
	private class OneWayListIterator<T> implements ListIterator<T> {

		private ListNode<T> Cursor;
		private ListNode<T> PreviousCursor;
		private ListNode<T> LastNavigationNode;
		private ListNode<T> PrevLastNavigationNode;
		private int Iteration;
		
		@SuppressWarnings("unchecked")
		public OneWayListIterator(int index) {
			Cursor = (ListNode<T>) FirstNode;
			PreviousCursor = null;
			LastNavigationNode = Cursor;
			PrevLastNavigationNode = PreviousCursor;
			Iteration = 0;
			while (Iteration != index) {
				next();
			}
		}

		@SuppressWarnings("unchecked")
		@Override
		public void add(T e) {
			ListNode<T> newNode = new ListNode<T>(e);
			if (Iteration > 0)
				PreviousCursor.NextNode = newNode;
			PreviousCursor = newNode;
			newNode.NextNode = Cursor;
			if(Iteration == 0)
				setFirstNode((ListNode<Object>) newNode);
			Size++;
			Iteration++;
		}

		@Override
		public boolean hasNext() {
			if (Iteration < Size)
				return true;
			return false;
		}

		// Method is not supported by this class
		@Override
		public boolean hasPrevious() {
			throw new UnsupportedOperationException();
		}

		@Override
		public T next() {
			if ((Iteration >= Size) || (Iteration < 0))
					throw new IndexOutOfBoundsException();
			LastNavigationNode = Cursor;
			PrevLastNavigationNode = PreviousCursor;
			T value = Cursor.getValue();
			PreviousCursor = Cursor;
			Cursor = Cursor.NextNode;
			Iteration++;
			return value;
		}

		@Override
		public int nextIndex() {
			return Iteration;
		}

		// Method is not supported by this class
		@Override
		public T previous() {
			throw new UnsupportedOperationException();
		}

		// Method is not supported by this class
		@Override
		public int previousIndex() {
			throw new UnsupportedOperationException();
		}

		@Override
		public void remove() {
			if (Iteration > 0)
				PrevLastNavigationNode.NextNode = LastNavigationNode.NextNode;
			LastNavigationNode = LastNavigationNode.NextNode;
			PreviousCursor = PrevLastNavigationNode;
			Cursor = LastNavigationNode;
			if (Iteration == 0)
				setFirstNode(Cursor);
			Size--;
		}

		@Override
		public void set(T e) {
			Cursor.setValue(e);
		}
		
	}

}
